
package com.jf.cloud.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.feign.SearchOrderFeignClient;
import com.jf.cloud.api.feign.SearchOrderRefundFeignClient;
import com.jf.cloud.api.leaf.feign.SegmentFeignClient;
import com.jf.cloud.api.multishop.bo.OrderChangeShopWalletAmountBO;
import com.jf.cloud.api.multishop.feign.ShopDetailFeignClient;
import com.jf.cloud.api.multishop.feign.ShopRefundAddrFeignClient;
import com.jf.cloud.api.multishop.feign.ShopWalletFeignClient;
import com.jf.cloud.api.multishop.vo.ShopDetailVO;
import com.jf.cloud.api.multishop.vo.ShopRefundAddrVO;
import com.jf.cloud.api.order.bo.EsOrderRefundBO;
import com.jf.cloud.api.order.constant.BuyerReasonType;
import com.jf.cloud.api.order.constant.OrderStatus;
import com.jf.cloud.api.order.vo.AccountOrderDetailVO;
import com.jf.cloud.api.order.vo.OrderRefundProdEffectRespVO;
import com.jf.cloud.api.order.vo.OrderRefundSimpleVO;
import com.jf.cloud.api.order.vo.PageShopAccountOrderVO;
import com.jf.cloud.api.seckill.dto.SecKillRefundDTO;
import com.jf.cloud.api.seckill.feign.SeckillFeignClient;
import com.jf.cloud.api.seckill.vo.SeckillApiVO;
import com.jf.cloud.api.supplier.feign.SupplierRefundAddrFeignClient;
import com.jf.cloud.api.supplier.vo.SupplierApiRefundAddrVO;
import com.jf.cloud.api.vo.EsPageVO;
import com.jf.cloud.common.cache.constant.OrderCacheNames;
import com.jf.cloud.common.cache.util.RedisUtil;
import com.jf.cloud.common.constant.Constant;
import com.jf.cloud.common.constant.DistributedIdKey;
import com.jf.cloud.common.constant.SendTypeEnum;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.i18n.LanguageEnum;
import com.jf.cloud.common.order.bo.RefundNotifyBO;
import com.jf.cloud.common.order.bo.RefundReductionStockBO;
import com.jf.cloud.common.order.constant.*;
import com.jf.cloud.common.order.dto.OrderRefundSearchDTO;
import com.jf.cloud.common.order.util.OrderLangUtil;
import com.jf.cloud.common.order.vo.*;
import com.jf.cloud.common.product.constant.PreSaleType;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.rocketmq.config.RocketMqConstant;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.common.util.PriceUtil;
import com.jf.cloud.order.bo.mongo.MongoOrderRefundBO;
import com.jf.cloud.order.bo.mongo.MongoOrderRefundItemBO;
import com.jf.cloud.order.constant.*;
import com.jf.cloud.order.dto.multishop.OrderRefundDTO;
import com.jf.cloud.order.manager.MongoOrderRefundManager;
import com.jf.cloud.order.mapper.OrderRefundMapper;
import com.jf.cloud.order.mapper.OrderRefundSettlementMapper;
import com.jf.cloud.order.model.*;
import com.jf.cloud.order.service.*;
import com.jf.cloud.order.vo.OrderRefundVO;
import ma.glasnost.orika.MapperFacade;
import org.apache.commons.collections.CollectionUtils;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单退款记录信息
 *
 * @author zz
 * @date 2020-12-05 14:13:50
 */
@Service
public class OrderRefundServiceImpl implements OrderRefundService {

    private static final Logger logger = LoggerFactory.getLogger(OrderRefundServiceImpl.class);

    @Autowired
    private OrderRefundMapper orderRefundMapper;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private OrderRefundAddrService orderRefundAddrService;
    @Autowired
    private ShopRefundAddrFeignClient shopRefundAddrFeignClient;
    @Autowired
    private SupplierRefundAddrFeignClient supplierRefundAddrFeignClient;
    @Autowired
    private OrderRefundSettlementMapper orderRefundSettlementMapper;
    @Autowired
    private RocketMQTemplate orderRefundSuccessServiceTemplate;
    @Autowired
    private RocketMQTemplate orderRefundSuccessSettlementTemplate;
    @Autowired
    private RocketMQTemplate refundSuccessNotifySupplierTemplate;
    @Autowired
    private RocketMQTemplate orderRefundSuccessStockTemplate;
    @Autowired
    private RocketMQTemplate sendNotifyToShopTemplate;
    @Autowired
    private RocketMQTemplate sendNotifyToUserTemplate;
    @Autowired
    private RocketMQTemplate seckillOrderRefundMqTemplate;
    @Autowired
    private SeckillFeignClient seckillFeignClient;
    @Autowired
    private MapperFacade mapperFacade;
    @Autowired
    private RocketMQTemplate orderRefundTemplate;
    @Autowired
    private OrderSettlementService orderSettlementService;
    @Autowired
    private SegmentFeignClient segmentFeignClient;
    @Autowired
    private MongoOrderRefundManager mongoOrderRefundManager;
    @Autowired
    private SearchOrderFeignClient searchOrderFeignClient;
    @Autowired
    private SearchOrderRefundFeignClient searchOrderRefundFeignClient;
    @Autowired
    private ShopDetailFeignClient shopDetailFeignClient;
    @Autowired
    private ShopWalletFeignClient shopWalletFeignClient;

    @Override
    public EsPageVO<EsOrderRefundVO> page(PageDTO pageDTO, OrderRefundSearchDTO orderRefundPage) {
        orderRefundPage.setPageNum(pageDTO.getPageNum());
        orderRefundPage.setPageSize(pageDTO.getPageSize());
        // 替换成es的分页查询
        ServerResponseEntity<EsPageVO<EsOrderRefundVO>> orderRefundResponseEntity = searchOrderRefundFeignClient.pageOrderRefund(orderRefundPage);
        if (orderRefundResponseEntity.isFail()) {
            logger.error("查询订单退款记录信息失败，失败原因：{}", orderRefundResponseEntity.getMsg());
            throw new LuckException(orderRefundResponseEntity.getMsg());
        }
        return orderRefundResponseEntity.getData();
    }
//    public PageVO<OrderRefundVO> page(PageDTO pageDTO, OrderRefundPageDTO orderRefundPageDTO,Integer type) {
//        PageVO<OrderRefundVO> pageVO = new PageVO<>();
//        Long refundCount = orderRefundMapper.count(orderRefundPageDTO);
//        pageVO.setTotal(refundCount);
//        pageVO.setPages(PageUtil.getPages(pageVO.getTotal(), pageDTO.getPageSize()));
//        // 没有退款的订单返回空
//        if (Objects.equals(refundCount, 0L)) {
//            pageVO.setList(Collections.emptyList());
//            return pageVO;
//        }
//
//        List<OrderRefundVO> orderRefundList = orderRefundMapper.list(orderRefundPageDTO, new PageAdapter(pageDTO));
//        for (OrderRefundVO orderRefundVO : orderRefundList) {
//            List<RefundOrderItemVO> orderItems = orderRefundVO.getOrderItems();
//            // 不是整单退款
//            if (!Objects.equals(orderRefundVO.getRefundType(), RefundType.ALL.value())) {
//                orderItems.removeIf(next -> !Objects.equals(orderRefundVO.getOrderItemId(), next.getOrderItemId()));
//            }
//            OrderLangUtil.orderRefundVOList(orderItems);
//            orderRefundVO.setBuyerReasonValue(BuyerReasonType.instance(orderRefundVO.getBuyerReason()).getCn());
//            getRefundTypeByOrderItem(orderRefundVO, type);
//        }
//        pageVO.setList(orderRefundList);
//        return pageVO;
//    }

    @Override
    public OrderRefundVO getByRefundId(Long refundId) {
        return orderRefundMapper.getByRefundId(refundId);
    }

    @Override
    public OrderRefundVO getDetailByRefundId(Long refundId) {
//        OrderRefundVO orderRefundVO = orderRefundMapper.getDetailByRefundId(refundId);
        OrderRefundVO orderRefundVO = orderRefundMapper.getByRefundId(refundId);
        // 获取订单数据
        Order order = orderService.getOrderAndOrderItemData(orderRefundVO.getOrderId(), orderRefundVO.getShopId());
        orderRefundVO.setPayTime(order.getPayTime());
        orderRefundVO.setActualTotal(order.getActualTotal());
        orderRefundVO.setOrderStatus(order.getStatus());
        orderRefundVO.setRefundStatus(order.getRefundStatus());
        orderRefundVO.setShopName(order.getShopName());
        orderRefundVO.setOrderScore(order.getOrderScore());
        orderRefundVO.setOrderItems(new ArrayList<>());
        orderRefundVO.setPayType(order.getPayType());
        orderRefundVO.setPlatformFreeFreightAmount(order.getPlatformFreeFreightAmount());
        for (OrderItem orderItem : order.getOrderItems()) {
            RefundOrderItemVO refundOrderItemVO = mapperFacade.map(orderItem, RefundOrderItemVO.class);
            refundOrderItemVO.setRefundScore(orderItem.getUseScore());
            if (Objects.isNull(refundOrderItemVO.getRefundScore())) {
                refundOrderItemVO.setRefundScore(0L);
            }
            orderRefundVO.getOrderItems().add(refundOrderItemVO);
        }

        orderRefundVO.setBuyerReasonValue(BuyerReasonType.instance(orderRefundVO.getBuyerReason()).getCn());
        List<RefundOrderItemVO> orderItems = orderRefundVO.getOrderItems();
        getRefundTypeByOrderItem(orderRefundVO, orderRefundVO.getRefundType());
        // 不是整单退款
        if (!Objects.equals(orderRefundVO.getRefundType(), RefundType.ALL.value())) {
            logger.info("不是整单退款，退款订单项信息：{}", orderItems);
            orderItems.removeIf(next -> !Objects.equals(orderRefundVO.getOrderItemId(), next.getOrderItemId()));
        }
        OrderLangUtil.orderRefundVOList(orderRefundVO.getOrderItems());
        return orderRefundVO;
    }


    @Override
    public void save(OrderRefund orderRefund) {
        Long userId = AuthUserContext.get().getUserId();
        orderRefund.setRefundId(segmentFeignClient.getSegmentIdWithDateTime(DistributedIdKey.MALL4CLOUD_REFUND, userId).getData());
        orderRefundMapper.save(orderRefund);
    }

    @Override
    public void update(OrderRefund orderRefund) {
        orderRefundMapper.update(orderRefund);
    }

    @Override
    public void deleteById(Long refundId) {
        orderRefundMapper.deleteById(refundId);
    }

    @Override
    public boolean checkRefundDate(Order order) {
        // 判断是否超过支持的退款天数
        if (Objects.equals(order.getStatus(), OrderStatus.SUCCESS.value())) {
            long finallyTime = order.getFinallyTime().getTime();
            long currentTime = System.currentTimeMillis();
            int miniTime = Constant.MAX_FINALLY_REFUND_TIME * 24 * 60 * 60 * 1000;
            return currentTime - finallyTime <= miniTime;
        }
        return true;
    }

    @Override
    public List<OrderRefund> getProcessOrderRefundByOrderId(Long orderId) {
        return orderRefundMapper.getProcessOrderRefundByOrderId(orderId);
    }

    /**
     * 生成退款单
     *
     * @param orderRefund 退款对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyRefund(OrderRefund orderRefund) {
        // 生成退款单
        save(orderRefund);
        // 更新订单状态
        Order order = new Order();
        order.setOrderId(orderRefund.getOrderId());
        order.setRefundStatus(RefundStatusEnum.APPLY.value());
        orderService.update(order);

        // 更新订单项状态
        if (Objects.equals(RefundType.ALL.value(), orderRefund.getRefundType())) {
            orderItemService.updateRefundStatusByOrderId(order.getOrderId(), RefundStatusEnum.APPLY.value());
            logger.info("整单退款，更新订单项状态为申请退款，订单id：{}", order.getOrderId());
        } else {
            OrderItem orderItem = new OrderItem();
            orderItem.setOrderItemId(orderRefund.getOrderItemId());
            orderItem.setRefundStatus(RefundStatusEnum.APPLY.value());
            orderItem.setFinalRefundId(orderRefund.getRefundId());
            orderItemService.update(orderItem);
            logger.info("部分退款，更新订单项状态为申请退款，订单项id：{}", orderItem.getOrderItemId());
        }
        //如果是赠品，需要处理关联赠品订单项
        List<OrderItemVO> giveawayOrderItems = orderItemService.getOrderItemByGiveawayOrderItemId(orderRefund.getUserId(), orderRefund.getOrderItemId());
        if (giveawayOrderItems.size() != 0) {
            logger.info("赠品退款，关联赠品订单项,更新订单项状态为申请退款，订单项id：{}", orderRefund.getOrderItemId());
            List<OrderItem> list = new ArrayList<>();
            for (OrderItemVO orderItemVO : giveawayOrderItems) {
                OrderItem orderItems = mapperFacade.map(orderItemVO, OrderItem.class);
                orderItems.setRefundStatus(RefundStatusEnum.APPLY.value());
                list.add(orderItems);
            }
            orderItemService.updateBatch(list);
        }
        // TODO -y 改为mysql查询
        // 消息推送-申请退款
        ServerResponseEntity<List<SendNotifyBO>> orderServerResponseEntity = searchOrderFeignClient.listSendNotifyByOrderIds(Collections.singletonList(orderRefund.getOrderId()));
        if (orderServerResponseEntity.isFail()) {
            logger.error("查询订单信息失败，订单id：{}", orderRefund);
            throw new LuckException(orderServerResponseEntity.getMsg());
        }
        SendNotifyBO notifyBO = orderServerResponseEntity.getData().get(0);
        notifyBO.setPrice(PriceUtil.toDecimalPrice(orderRefund.getRefundAmount()).toString());
        notifyBO.setSendType(SendTypeEnum.LAUNCH_REFUND.getValue());
        notifyBO.setBizId(orderRefund.getOrderId());
        notifyBO.setRemark(orderRefund.getBuyerDesc());
        notifyBO.setRejectMessage(BuyerReasonType.instance(orderRefund.getBuyerReason()).getCn());
        SendStatus sendBizStatus = sendNotifyToShopTemplate.syncSend(RocketMqConstant.SEND_NOTIFY_TO_SHOP_TOPIC, new GenericMessage<>(notifyBO)).getSendStatus();
//        if (!Objects.equals(sendBizStatus, SendStatus.SEND_OK)) {
//            // 这个回调方法会多次进行回调
//            logger.warn("推送退款成功消息失败，退款id为："+ orderRefund.getRefundId());
//        }
    }

    @Override
    public ServerResponseEntity<Void> agreeRefund(OrderRefundDTO orderRefundParam, OrderRefundVO orderRefundVo) {
        OrderSettlement orderSettlement = orderSettlementService.getByOrderId(orderRefundVo.getOrderId());
        orderRefundVo.setPayId(orderSettlement.getPayId());
        orderRefundVo.setPayType(orderSettlement.getPayType());

        // -----最后一件运费计算-----------
        long freightAmount = 0L;
        orderRefundVo.setFreightAmount(0L);
        // 获取订单信息
        Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVo.getOrderId(), orderRefundVo.getUserId());
        if (Objects.equals(order.getStatus(), OrderStatus.PAYED.value())) {
            // 如果存在分销订单，则计算分销总金额
            List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderIds(order.getOrderId());
            // 获取所有的订单项总数
            int orderItemCount = orderItemList.size();
            //退款成功总数
            // 获取所有正在进行中的退款订单
            int refundCount = countSuccessItemNum(order.getOrderId());
            //最后一单
            if (Objects.equals(refundCount, orderItemCount - 1)) {
                if (order.getFreightAmount() > 0.0 && order.getPlatformFreeFreightAmount() >= 0.0) {
                    freightAmount = order.getFreightAmount() - order.getPlatformFreeFreightAmount();
                    logger.info("最后一单运费计算：freightAmount={},platformFreeFreightAmount={}", freightAmount, order.getPlatformFreeFreightAmount());
                }
                // 单项退款，且平台减免运费---平台减免的运费要从商家钱包退还给平台，所以将运费添加到平台优惠金额中
                if (Objects.equals(orderRefundVo.getRefundType(), RefundType.SINGLE.value()) && order.getPlatformFreeFreightAmount() > 0.0) {
                    orderRefundVo.setPlatformRefundAmount(orderRefundVo.getPlatformRefundAmount() + order.getPlatformFreeFreightAmount());
                    logger.info("单项退款，且平台减免运费,平台减免的运费要从商家钱包退还给平台，所以将运费添加到平台优惠金额中：platformRefundAmount={}", orderRefundVo.getPlatformRefundAmount());
                }
            }
            // 供应商发货的订单，放进去实际的支付运费金额，用于后续的供应商金额退款
            if (Objects.equals(order.getSupplierDeliveryType(), 1) && !Objects.equals(order.getSupplierId(), 0L)) {
                orderRefundVo.setFreightAmount(freightAmount + Math.abs(order.getFreeFreightAmount()));
                logger.info("供应商发货的订单，放进去实际的支付运费金额，用于后续的供应商金额退款：freightAmount={}", orderRefundVo.getFreightAmount());
            }
        }
        // 如果是定金预售，需要注意下是两笔退款
        if (Objects.equals(order.getPreSaleType(), PreSaleType.DEPOSIT.value())) {
            orderRefundVo.setPayIds(orderSettlement.getPayIds());
            logger.info("定金预售，需要注意下是两笔退款：payIds={}", orderSettlement.getPayIds());
        }
        // 只有单个退款才需要加上运费
        if (Objects.equals(orderRefundVo.getRefundType(), RefundType.SINGLE.value())) {
            orderRefundVo.setRefundAmount(orderRefundVo.getRefundAmount() + freightAmount);
            logger.info("单个退款需要加上运费：refundAmount={}", orderRefundVo.getRefundAmount());
        }
        // 执行退款，真正意义上的退款，需要确保
        // 发送事务消息
        TransactionSendResult transactionSendResult = orderRefundTemplate.sendMessageInTransaction(RocketMqConstant.ORDER_REFUND_TOPIC, new GenericMessage<>(orderRefundVo), orderRefundParam);

        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            logger.error("退款事务消息发送失败，事务状态：{}", transactionSendResult.getLocalTransactionState());
            return ServerResponseEntity.fail(ResponseEnum.EXCEPTION);
        }
        return ServerResponseEntity.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyRefundByUnreal(com.jf.cloud.order.dto.multishop.OrderRefundDTO  orderRefundParam) {
        // 处理退款操作
        OrderRefundVO orderRefundVO = getDetailByRefundId(orderRefundParam.getRefundId());
        if (!Objects.equals(ReturnProcessStatusEnum.APPLY.value(), orderRefundVO.getReturnMoneySts())) {
            // 订单退款状态已发生改变，请勿重复操作
            logger.error("订单退款状态已发生改变，请勿重复操作");
            return;
        }

        // 拒绝退款，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.DISAGREE.value())) {
            orderRefundVO.setSupplierHandleStatus(null);
            disagreeRefund(orderRefundParam, orderRefundVO);
        }
        if(!Objects.equals(orderRefundVO.getSupplierId(),0L)) {
            // 移交供应商处理，改变下状态即可
            if (Objects.equals(orderRefundParam.getSupplierHandleStatus(), SupplierHandleStatus.TRANSFER_SUPPLIER.value())) {
                transferRefundOrderToSupplier(orderRefundParam, orderRefundVO);
            }
            if(!Objects.equals(orderRefundParam.getSupplierHandleStatus(), SupplierHandleStatus.NORMAL.value())){
                logger.error("供应商订单只能选择自行处理或者移交供应商处理");
                return;
            }
            Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVO.getOrderId(), orderRefundVO.getUserId());
            // 不是待采购状态的供应商订单，才检查下钱是否足够
            if(!Objects.equals(order.getWaitPurchase(),1)) {
                // 检查一下商家结算金额是否足够
                ServerResponseEntity<Long> amountResp = shopWalletFeignClient.getSettlementAmountByShopId(orderRefundVO.getShopId());
                if (!amountResp.isSuccess()) {
                    throw new LuckException(amountResp.getMsg());
                }
                // 供应商改变金额 = 供应商改变金额 - 平台供应商佣金改变量
                Long supplierRealRefundAmount = orderRefundVO.getPurchaseRefundAmount() - orderRefundVO.getPurPlatformRefundCommission();
                if (amountResp.getData() < supplierRealRefundAmount) {
                    logger.error("商家余额不足，请去进行充值后重试");
                    return;
                }
            }
        }

        // 同意退货，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundVO.getApplyType(), RefundApplyType.REFUND_AND_RETURNS.value())) {
            agreeReturns(orderRefundParam, orderRefundVO, SysTypeEnum.MULTISHOP.value());
        }
        // 同意退款，上面只是同意退货，关系到钱要看下面的
        agreeRefundUnreal(orderRefundParam,orderRefundVO);
    }


    /**
     * 买家提交物流信息
     *
     * @param orderRefund     退款单对象
     * @param orderRefundAddr 退款物流单对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitExpress(OrderRefund orderRefund, OrderRefundAddr orderRefundAddr) {
        orderRefundAddrService.update(orderRefundAddr);

        // 更新退款单信息
        if (!Objects.equals(ReturnProcessStatusEnum.CONSIGNMENT.value(), orderRefund.getReturnMoneySts())) {
            orderRefund.setReturnMoneySts(ReturnProcessStatusEnum.CONSIGNMENT.value());
            logger.info("买家提交物流信息，更新退款单状态为买家已发货，退款单id：{}", orderRefund.getRefundId());
        }
        orderRefund.setDeliveryTime(new Date());
        orderRefund.setUpdateTime(new Date());
        update(orderRefund);

        // 消息推送-用户已退货
        ServerResponseEntity<List<SendNotifyBO>> orderServerResponseEntity = searchOrderFeignClient.listSendNotifyByOrderIds(Collections.singletonList(orderRefund.getOrderId()));
        if (orderServerResponseEntity.isFail()) {
            throw new LuckException(orderServerResponseEntity.getMsg());
        }
        SendNotifyBO notifyBO = orderServerResponseEntity.getData().get(0);
        notifyBO.setPrice(PriceUtil.toDecimalPrice(orderRefund.getRefundAmount()).toString());
        //供应商处理的退款，给供应商发送用户退货提醒
        // 供应商处理状态， -1.商家自行处理 0.待供应商处理 1.供应商已同意 2.供应商已拒绝
        if (!Objects.equals(orderRefund.getSupplierHandleStatus(), -1)) {
            notifyBO.setShopId(null);
            notifyBO.setSupplierId(orderRefund.getSupplierId());
            notifyBO.setSendType(SendTypeEnum.RETURN_REFUND_TO_SUPPLIER.getValue());
        } else {
            notifyBO.setSendType(SendTypeEnum.RETURN_REFUND.getValue());
        }
        notifyBO.setBizId(orderRefund.getOrderId());
        notifyBO.setRemark(orderRefund.getBuyerDesc());
        notifyBO.setRejectMessage(BuyerReasonType.instance(orderRefund.getBuyerReason()).getCn());
        SendStatus sendBizStatus = sendNotifyToShopTemplate.syncSend(RocketMqConstant.SEND_NOTIFY_TO_SHOP_TOPIC, new GenericMessage<>(notifyBO)).getSendStatus();

        //notifyTemplateService.sendNotifyByUserRefundDelivery(order, SendType.RETURN_REFUND);
    }

    @Override
    public Integer countByReturnMoneyStsAndOrderId(Integer returnMoneySts, Integer returnMoneySts2, Long orderId) {
        return orderRefundMapper.countByReturnMoneyStsAndOrderId(returnMoneySts, returnMoneySts2, orderId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void agreeReturns(OrderRefundDTO orderRefundParam, OrderRefundVO orderRefundVO, Integer sysType) {
        if (Objects.isNull(orderRefundParam.getShopRefundAddrId())) {
            throw new LuckException("请设置退货物流信息");
        }
        // 同意退款退货操作
        // 设置退货物流信息
        if (Objects.equals(sysType, SysTypeEnum.SUPPLIER.value())) {
            ServerResponseEntity<SupplierApiRefundAddrVO> refundAddrResponse = supplierRefundAddrFeignClient.getSupplierRefundAddrByRefundAddrId(orderRefundParam.getShopRefundAddrId());
            if (!refundAddrResponse.isSuccess() || refundAddrResponse.getData() == null) {
                throw new LuckException("请设置退货物流信息");
            }
            SupplierApiRefundAddrVO refundAddr = refundAddrResponse.getData();
            OrderRefundAddr orderRefundAddr = new OrderRefundAddr();
            orderRefundAddr.setShopId(orderRefundVO.getShopId());
            orderRefundAddr.setRefundId(orderRefundVO.getRefundId());
            orderRefundAddr.setUserId(orderRefundVO.getUserId());
            orderRefundAddr.setConsigneeName(refundAddr.getConsignee());
            orderRefundAddr.setConsigneeMobile(refundAddr.getMobile());
            orderRefundAddr.setConsigneePostCode(refundAddr.getPostCode());
            String addr = refundAddr.getProvince() + refundAddr.getCity() + refundAddr.getArea() + refundAddr.getAddr();
            orderRefundAddr.setConsigneeAddr(addr);
            orderRefundAddrService.save(orderRefundAddr);
        } else {
            ServerResponseEntity<ShopRefundAddrVO> refundAddrResponse = shopRefundAddrFeignClient.getShopRefundAddrByRefundAddrId(orderRefundParam.getShopRefundAddrId());
            if (!refundAddrResponse.isSuccess() || refundAddrResponse.getData() == null) {
                throw new LuckException("请设置退货物流信息");
            }
            ShopRefundAddrVO refundAddr = refundAddrResponse.getData();
            OrderRefundAddr orderRefundAddr = new OrderRefundAddr();
            orderRefundAddr.setShopId(orderRefundVO.getShopId());
            orderRefundAddr.setRefundId(orderRefundVO.getRefundId());
            orderRefundAddr.setUserId(orderRefundVO.getUserId());
            orderRefundAddr.setConsigneeName(refundAddr.getConsignee());
            orderRefundAddr.setConsigneeMobile(refundAddr.getMobile());
            orderRefundAddr.setConsigneePostCode(refundAddr.getPostCode());
            String addr = refundAddr.getProvince() + refundAddr.getCity() + refundAddr.getArea() + refundAddr.getAddr();
            orderRefundAddr.setConsigneeAddr(addr);
            orderRefundAddrService.save(orderRefundAddr);
        }


        int agreeStats = orderRefundMapper.agreeReturns(orderRefundParam.getSellerMsg(), orderRefundVO.getRefundId());
        if (agreeStats == 0) {
            throw new LuckException("订单退款状态已发生改变，请勿重复操作");
        }
        // TODO 消息推送--同意退款
        List<SendNotifyBO> notifyBOList = orderService.listSendNotifyBOByOrderIds(Collections.singletonList(orderRefundVO.getOrderId()));
        SendNotifyBO sendNotifyBO = notifyBOList.get(0);
        sendNotifyBO.setSendType(SendTypeEnum.AGREE_REFUND.getValue());
        sendNotifyBO.setPrice(PriceUtil.toDecimalPrice(orderRefundVO.getRefundAmount()).toString());
        SendStatus sendBizStatus = sendNotifyToUserTemplate.syncSend(RocketMqConstant.SEND_NOTIFY_TO_USER_TOPIC, new GenericMessage<>(notifyBOList)).getSendStatus();
//        // 如果是供应商订单，且商家自行处理，这里锁定一下商家的已结算金额
//        if(!Objects.equals(orderRefundVO.getSupplierId(),0L) && Objects.equals(orderRefundParam.getSupplierHandleStatus(), SupplierHandleStatus.NORMAL.value())) {
//            SendStatus sendUpdateWalletStatus = sendNotifyToUserTemplate.syncSend(RocketMqConstant.LOCK_SHOP_WALLET_AMOUNT_TOPIC, new GenericMessage<>(notifyBOList)).getSendStatus();
//            if (!Objects.equals(sendUpdateWalletStatus,SendStatus.SEND_OK)) {
//                throw new LuckException(ResponseEnum.EXCEPTION);
//            }
//        }
    }

    @Override
    public Boolean getIsLastRefund(Long refundId, Long shopId) {
        OrderRefundVO orderRefundVo = getDetailByRefundId(refundId);
        if (Objects.isNull(orderRefundVo)) {
            //退款单不存在
            logger.error("退款单不存在");
            throw new LuckException("退款单不存在");
        }
        if (Objects.equals(orderRefundVo.getRefundType(), RefundType.ALL.value())) {
            //整单退款
            logger.info("整单退款");
            return false;
        }
        if (Objects.equals(orderRefundVo.getApplyType(), RefundApplyType.REFUND_AND_RETURNS.value())) {
            //退货退款
            logger.info("退货退款");
            return false;
        }
        Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVo.getOrderId(), orderRefundVo.getUserId());
        if (!Objects.equals(order.getStatus(), OrderStatus.PAYED.value())) {
            //非待发货
            logger.info("非待发货");
            return false;
        }
        // 如果存在分销订单，则计算分销总金额
        List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderIds(order.getOrderId());
        // 获取所有的订单项总数
        int orderItemCount = orderItemList.size();
        //退款成功总数
        // 获取所有正在进行中的退款订单
        int refundCount = countSuccessItemNum(order.getOrderId());
        return Objects.equals(refundCount, orderItemCount - 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void refundSuccess(RefundNotifyBO refundNotifyBO) {
        Long refundId = refundNotifyBO.getRefundId();
        OrderRefundVO orderRefundVO = orderRefundMapper.getByRefundId(refundId);
        // 已经进行过退款了
        if (Objects.equals(orderRefundVO.getReturnMoneySts(), ReturnProcessStatusEnum.SUCCESS.value())) {
            return;
        }


        OrderRefund orderRefund = new OrderRefund();
        orderRefund.setRefundId(refundId);
        orderRefund.setRefundTime(new Date());
        if (Objects.equals(orderRefundVO.getSupplierHandleStatus(), SupplierHandleStatus.TRANSFER_SUPPLIER.value())) {
            orderRefund.setSupplierHandleStatus(SupplierHandleStatus.SUPPLIER_AGREE.value());
        }
        orderRefund.setReturnMoneySts(ReturnProcessStatusEnum.SUCCESS.value());
        // 更新退款状态
        orderRefundMapper.update(orderRefund);
        // 更新结算单状态
        int updateStatus = orderRefundSettlementMapper.updateToSuccessByRefundId(refundId);
        if (updateStatus < 1) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        Order dbOrder = orderService.getByOrderId(refundNotifyBO.getOrderId());
        OrderItemVO dbOrderItem = orderItemService.getByOrderItemId(orderRefundVO.getOrderItemId());
        Order order = new Order();

        // 处理订单退款更新
        this.handleOrderRefund(refundNotifyBO, orderRefundVO, dbOrder, order, dbOrderItem);
        // 还原库存和商品销量
        this.reductionStock(orderRefundVO, dbOrder, dbOrderItem);
        boolean canRefundFlag = Objects.equals(dbOrder.getStatus(), OrderStatus.PAYED.value())
                || Objects.equals(dbOrder.getStatus(), OrderStatus.CONSIGNMENT.value())
                || Objects.equals(dbOrder.getStatus(), OrderStatus.SUCCESS.value());
        // 退款订单关闭，还原优惠券以及订单结算
        if (canRefundFlag && Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
            // 订单在已支付，已发货，确认收货的情况下，退款导致订单关闭
            // 需要判断下是否要进行结算给商家的操作，这个结算的计算是退款完成后结算的，所以不要随便改变顺序
            handlePartialRefund(dbOrder, orderRefundVO);
        }
        refundNotifyBO.setCanRefund(canRefundFlag);
        refundNotifyBO.setOrderStatus(order.getStatus());
        refundNotifyBO.setDbOrderStatus(dbOrder.getStatus());
        refundNotifyBO.setUserId(dbOrder.getUserId());
        refundNotifyBO.setOrderScore(dbOrder.getOrderScore());
        // 通知还原优惠券&&还原成长值&&退还积分
        SendStatus sendStatus = orderRefundSuccessServiceTemplate.syncSend(RocketMqConstant.ORDER_REFUND_SUCCESS_SERVICE_TOPIC, new GenericMessage<>(refundNotifyBO)).getSendStatus();
        if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        OrderRefundVO orderRefundDb = orderRefundMapper.getByRefundId(orderRefund.getRefundId());

        OrderSettlement orderSettlement = orderSettlementService.getByOrderId(refundNotifyBO.getOrderId());
        OrderRefundVO orderRefundVo = new OrderRefundVO();
        orderRefundVo.setRefundId(refundNotifyBO.getRefundId());
        orderRefundVo.setRefundAmount(orderRefundDb.getRefundAmount());
        orderRefundVo.setOrderId(order.getOrderId());
        orderRefundVo.setPayId(orderSettlement.getPayId());
        orderRefundVo.setPayType(orderSettlement.getPayType());
        orderRefundVo.setRefundType(RefundType.ALL.value());
        orderRefundVo.setPlatformRefundAmount(orderRefundDb.getPlatformRefundAmount());
        orderRefundVo.setShopId(orderRefundDb.getShopId());
        orderRefundVo.setPlatformRefundCommission(orderRefundDb.getPlatformRefundCommission());
        orderRefundVo.setPurPlatformRefundCommission(orderRefundDb.getPurPlatformRefundCommission());
        orderRefundVo.setPurchaseRefundAmount(orderRefundDb.getPurchaseRefundAmount());
        orderRefundVo.setWaitPurchase(dbOrder.getWaitPurchase());
        orderRefundVo.setFreightAmount(dbOrder.getFreightAmount());
        orderRefundVo.setUnSuccessGroupOrder(1);

        SendStatus sendStockStatus = orderRefundTemplate.syncSend(RocketMqConstant.ORDER_REFUND_TOPIC, new GenericMessage<>(orderRefundVo)).getSendStatus();
        if (!Objects.equals(sendStockStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }
    }

    /**
     * 处理订单退款更新
     *
     * @param refundNotifyBO 退款通知
     * @param orderRefundVO  订单退款信息
     * @param dbOrder        订单信息
     * @param order          订单更新数据
     * @param dbOrderItem    订单项信息
     */
    private void handleOrderRefund(RefundNotifyBO refundNotifyBO, OrderRefundVO orderRefundVO, Order dbOrder, Order order, OrderItemVO dbOrderItem) {
        order.setOrderId(refundNotifyBO.getOrderId());
        if (Objects.equals(orderRefundVO.getRefundType(), RefundType.ALL.value())) {
            order.setStatus(OrderStatus.CLOSE.value());
        } else {
            // 查看是否已经达到了所有的订单商品数量，如是则订单关闭
            // 已退款单
            Integer refundSuccessRefundCount = orderRefundMapper.countRefundSuccessRefundCountByOrderId(refundNotifyBO.getOrderId());
            Integer itemNum = orderItemService.sumNumByOrderId(refundNotifyBO.getOrderId());
            // 整个订单完成退款的时候
            if (refundSuccessRefundCount >= itemNum) {
                order.setStatus(OrderStatus.CLOSE.value());
            } else {
                order.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
            }

            // 退款成功后，订单没有关闭，且订单为待发货，减少订单待发货商品数量
            if (!Objects.equals(order.getStatus(), OrderStatus.CLOSE.value()) && Objects.equals(dbOrder.getStatus(), OrderStatus.PAYED.value())) {
                Long orderItemId = orderRefundVO.getOrderItemId();
                // 减少订单待发货商品数量
                orderItemService.reduceUnDeliveryNumByOrderItemId(orderItemId, orderRefundVO.getRefundCount());
                //
                int unDeliveryNum = orderItemService.countUnDeliveryNumByOrderId(refundNotifyBO.getOrderId());
                if (Objects.equals(unDeliveryNum, 0)) {
                    // 如果订单为快递发货情况，查询所有的订单项发货情况，如果有个是快递发货则是快递发货，否则全是无需快递则订单也为无需快递方式。
                    if (Objects.equals(dbOrder.getDeliveryType(), DeliveryType.DELIVERY.value())) {
                        List<OrderItemVO> orderItemList = orderItemService.listOrderItemAndLangByOrderId(refundNotifyBO.getOrderId());
                        int deliveryType = DeliveryType.NOT_DELIVERY.value();
                        for (OrderItemVO orderItemVO : orderItemList) {
                            if (Objects.nonNull(orderItemVO.getDeliveryType()) && Objects.equals(orderItemVO.getDeliveryType(), DeliveryType.DELIVERY.value())) {
                                deliveryType = DeliveryType.DELIVERY.value();
                                break;
                            }
                        }
                        order.setDeliveryType(deliveryType);
                    }
                    order.setStatus(OrderStatus.CONSIGNMENT.value());
                    order.setDeliveryTime(new Date());
                }
            }
        }
        if (Objects.equals(order.getStatus(), OrderStatus.CLOSE.value())) {
            order.setCancelTime(new Date());
            order.setUpdateTime(new Date());
            order.setCloseType(OrderCloseType.REFUND.value());
            order.setRefundStatus(RefundStatusEnum.SUCCEED.value());
        }
        // 更新订单项状态
        if (Objects.equals(orderRefundVO.getRefundType(), RefundType.ALL.value())) {
            orderItemService.updateRefundStatusByOrderId(order.getOrderId(), RefundStatusEnum.SUCCEED.value());
        } else {
            OrderItem orderItem = new OrderItem();
            orderItem.setOrderItemId(orderRefundVO.getOrderItemId());
            // 因为我们商城目前设计为一个订单项只能进行一次退款，无法进行多次退款
            if (dbOrderItem.getCount() > orderRefundVO.getRefundCount()) {
                orderItem.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
            } else {
                orderItem.setRefundStatus(RefundStatusEnum.SUCCEED.value());
            }
            orderItemService.update(orderItem);
        }
        orderService.update(order);
    }

    /**
     * 处理下部分退款完成，订单关闭的时候未结算变成已结算的金额处理，退款超时定时任务。
     *
     * @param order         订单信息
     * @param orderRefundVO
     */
    private void handlePartialRefund(Order order, OrderRefundVO orderRefundVO) {
        // 待采购订单退款不需要结算
//        if (Objects.equals(order.getWaitPurchase(), PurchaseOrderWaitStatus.WAIT_PURCHASE.value())) {
//            return;
//        }
        // 1.获取到部分退款并且订单关闭后，需要结算给商家、平台的钱
        // 获取所有正在进行中的退款订单
        OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO = getPartialRefundOrderChangeShopWalletAmountBO(order, orderRefundVO);
        // 商家要结算的钱 -  实际金额 - 退款金额
        long partialRefundAmount = order.getActualTotal() - orderChangeShopWalletAmountBO.getRefundAmount();

        // 已发货的订单，如果有平台优惠的运费金额，结算时要把钱给到商家
        if (!Objects.equals(order.getStatus(), OrderStatus.PAYED)) {
            partialRefundAmount = partialRefundAmount + orderChangeShopWalletAmountBO.getPlatformFreeFreightAmount();
        }


        // 如果商家和供应商需要结算的钱都为0，则不需要进行结算了
        if (partialRefundAmount > 0) {
            // 2.发送消息给商家，将需要结算的钱进行结算
            SendStatus sendStatus = orderRefundSuccessSettlementTemplate.syncSend(RocketMqConstant.ORDER_REFUND_SUCCESS_SETTLEMENT_TOPIC, new GenericMessage<>(orderChangeShopWalletAmountBO)).getSendStatus();
            if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
            // 因为商家结算这里也有结算供应商，所以直接return
            return;
        }


        // 非供应商订单到这一步已经结束了
        if (Objects.equals(orderChangeShopWalletAmountBO.getSupplierId(), 0L)) {
            return;
        }

        // 供应商要结算的钱
        long supplierAmount = orderChangeShopWalletAmountBO.getChangePurchaseAmount() + orderChangeShopWalletAmountBO.getFreightAmount()
                - orderChangeShopWalletAmountBO.getChangePurchasePlatformCommission();

        if (supplierAmount > 0) {
            // 供应商 添加结算金额
            SendStatus sendSupplierStatus = refundSuccessNotifySupplierTemplate.syncSend(RocketMqConstant.ORDER_REFUND_SUCCESS_SETTLEMENT_SUPPLIER_TOPIC, new GenericMessage<>(orderChangeShopWalletAmountBO)).getSendStatus();
            if (!Objects.equals(sendSupplierStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }
    }

    private OrderChangeShopWalletAmountBO getPartialRefundOrderChangeShopWalletAmountBO(Order order, OrderRefundVO orderRefundVO) {
        List<OrderRefund> orderRefunds = getProcessOrderRefundByOrderId(order.getOrderId());
        long alreadyRefundAmount = 0L;
        long changePlatformCommission = 0L;
        long platformAllowanceAmount = 0L;
        long changePurchasePlatformCommission = 0L;
        long changePurchaseRefundAmount = 0L;
        long refundPurchaseRefundAmount = 0L;
        long refundPurchasePlatformCommission = 0L;
        long supplierFreightAmount = 0L;
        List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderId(order.getOrderId());
        long purchaseAmount = orderItemList.stream().mapToLong(OrderItem::getItemPurchaseAmount).sum();
        long purchasePlatformCommission = orderItemList.stream().mapToLong(OrderItem::getPurchasePlatformCommission).sum();
        for (OrderRefund orderRefund : orderRefunds) {
            alreadyRefundAmount += orderRefund.getRefundAmount();
            changePlatformCommission += orderRefund.getPlatformRefundCommission();
            platformAllowanceAmount += orderRefund.getPlatformRefundAmount();
            refundPurchaseRefundAmount += orderRefund.getPurchaseRefundAmount();
            refundPurchasePlatformCommission += orderRefund.getPurPlatformRefundCommission();
            if (!Objects.equals(orderRefund.getSupplierHandleStatus(), SupplierHandleStatus.NORMAL.value())) {
                changePurchaseRefundAmount += orderRefund.getPurchaseRefundAmount();
                changePurchasePlatformCommission += orderRefund.getPurPlatformRefundCommission();
            }
            if (Objects.equals(RefundType.ALL.value(), orderRefund.getRefundType())) {
                break;
            }
        }
        // 待发货的订单结算时，平台优惠金额要加上运费优惠的金额（待发货退款是要退运费的，所以这时要把平台优惠的运费也算上，下面计算改变金额时才不会重复计算运费的金额了）
        if (Objects.equals(order.getStatus(), OrderStatus.PAYED.value())) {
            platformAllowanceAmount = platformAllowanceAmount + order.getPlatformFreeFreightAmount();
        }
        OrderChangeShopWalletAmountBO orderChangeShopWalletAmountBO = new OrderChangeShopWalletAmountBO();
        orderChangeShopWalletAmountBO.setOrderStatus(order.getStatus());
        orderChangeShopWalletAmountBO.setRefundId(orderRefundVO.getRefundId());
        orderChangeShopWalletAmountBO.setActualTotal(order.getActualTotal());
        orderChangeShopWalletAmountBO.setRefundAmount(alreadyRefundAmount);
        orderChangeShopWalletAmountBO.setPlatformFreeFreightAmount(order.getPlatformFreeFreightAmount());
        orderChangeShopWalletAmountBO.setPlatformAllowanceAmount(order.getPlatformAmount() - platformAllowanceAmount);
        // 如果是待发货状态，运费要退给用户，此时供应商是不能加上运费
        if (Objects.equals(order.getStatus(), OrderStatus.PAYED.value()) && !Objects.equals(order.getSupplierId(), 0L)) {
            orderChangeShopWalletAmountBO.setFreightAmount(0L);
            // 如果是待发货状态且为商家自行处理且为采购，则还是需要加上运费，供应商可以收入一笔运费
            if (Objects.equals(orderRefundVO.getSupplierHandleStatus(), SupplierHandleStatus.NORMAL.value())) {
                supplierFreightAmount = order.getFreightAmount() - Math.abs(order.getFreeFreightAmount());
            }

            // 供应商发货订单的待采购订单-单项退款，如果有会员包邮，平台补贴金额中就会包含运费补贴的金额
            // 然而运费金额不需要从商家结算金额中扣除，因为平台补贴的运费金额虽然经过商家，但是最终给的是供应商，也就是说商家待结算金额中没有包含平台补贴的运费
            // 但这一步还不能直接从平台补贴金额中扣除，否则会导致结算记录中的平台补贴金额不正确（按目前逻辑，平台补贴金额是包含运费补贴金额的）
            // 因此添加一个供应商运费补贴金额，在下一步计算变化金额时再减去补贴的运费即可
            if (Objects.equals(order.getWaitPurchase(), 1) && order.getPlatformFreeFreightAmount() > 0) {
                orderChangeShopWalletAmountBO.setSupplierFreightAmount(order.getPlatformFreeFreightAmount());
            }
            refundPurchaseRefundAmount = purchaseAmount - refundPurchaseRefundAmount - orderChangeShopWalletAmountBO.getFreightAmount();
        } else {
            orderChangeShopWalletAmountBO.setFreightAmount(order.getFreightAmount() - Math.abs(order.getFreeFreightAmount()));
            refundPurchaseRefundAmount = purchaseAmount - refundPurchaseRefundAmount + orderChangeShopWalletAmountBO.getFreightAmount();
        }
        orderChangeShopWalletAmountBO.setOrderId(order.getOrderId());
        orderChangeShopWalletAmountBO.setShopId(order.getShopId());
        orderChangeShopWalletAmountBO.setPlatformCommission(order.getPlatformCommission());
        orderChangeShopWalletAmountBO.setChangePlatformCommission(changePlatformCommission);
        orderChangeShopWalletAmountBO.setDistributionAmount(order.getDistributionAmount());
        // 供应商金额
        orderChangeShopWalletAmountBO.setSupplierId(order.getSupplierId());
        orderChangeShopWalletAmountBO.setWaitPurchase(order.getWaitPurchase());
        // 商家自行处理金额 + 运费
//        long actualPurchaseAmount = purchaseAmount - refundPurchaseRefundAmount - orderChangeShopWalletAmountBO.getFreightAmount();
        orderChangeShopWalletAmountBO.setRefundPurchaseAmount(refundPurchaseRefundAmount);
        orderChangeShopWalletAmountBO.setChangePurchaseAmount(purchaseAmount + supplierFreightAmount - changePurchaseRefundAmount);
        orderChangeShopWalletAmountBO.setChangePurchasePlatformCommission(purchasePlatformCommission - changePurchasePlatformCommission);
        orderChangeShopWalletAmountBO.setRefundPurchasePlatformCommission(purchasePlatformCommission - refundPurchasePlatformCommission);
        return orderChangeShopWalletAmountBO;
    }

    private void reductionStock(OrderRefundVO orderRefundVO, Order dbOrder, OrderItemVO dbOrderItem) {
        // 订单待发货或待成团订单超时，结果就被取消了以及虚拟商品订单，还原库存
        if (Objects.equals(dbOrder.getStatus(), OrderStatus.PAYED.value()) || Objects.equals(dbOrder.getStatus(), OrderStatus.WAIT_GROUP.value()) || (dbOrder.getOrderMold() != null && dbOrder.getOrderMold() == 1)) {
            List<RefundReductionStockBO> refundReductionStocks;
            // 整单退款
            if (Objects.equals(orderRefundVO.getRefundType(), RefundType.ALL.value())) {
                List<OrderItem> orderItems = orderItemService.listOrderItemsByOrderId(orderRefundVO.getOrderId());
                refundReductionStocks = orderItems.stream().map(orderItem -> {
                    RefundReductionStockBO refundReductionStockBO = new RefundReductionStockBO();
                    refundReductionStockBO.setCount(orderItem.getCount());
                    refundReductionStockBO.setSkuId(orderItem.getSkuId());
                    refundReductionStockBO.setSpuId(orderItem.getSpuId());
                    refundReductionStockBO.setOrderId(orderRefundVO.getRefundId());
                    refundReductionStockBO.setShopId(orderRefundVO.getShopId());
                    refundReductionStockBO.setActivityId(orderItem.getActivityId());
                    if (Objects.equals(dbOrder.getSupplierDeliveryType(), 1) && !Objects.equals(dbOrder.getSupplierId(), 0L)) {
                        refundReductionStockBO.setSupplierProd(1);
                        refundReductionStockBO.setSkuId(orderItem.getSupplierSkuId());
                        refundReductionStockBO.setSpuId(orderItem.getSupplierSpuId());
                    }
                    return refundReductionStockBO;
                }).collect(Collectors.toList());
            } else {
                // 单个退单时，获取商品是否有赠品订单项，如果有，一并退还
                List<Long> orderItemIds = new ArrayList<>();
                orderItemIds.add(dbOrderItem.getOrderItemId());
                Object result = RedisUtil.get(OrderCacheNames.REFUND_GIVEAWAY_ORDER_ITEM + dbOrderItem.getOrderItemId());
                if(Objects.nonNull(result)){
                    List<Long> giveawayOrderItemList = JSONObject.parseArray(result.toString(), Long.class);
                    orderItemIds.addAll(giveawayOrderItemList);
                }
                List<OrderItem> orderItemList = orderItemService.listByIds(orderItemIds);
                refundReductionStocks = orderItemList.stream().map(orderItem -> {
                    RefundReductionStockBO refundReductionStockBO = new RefundReductionStockBO();
                    refundReductionStockBO.setCount(orderItem.getCount());
                    refundReductionStockBO.setSkuId(orderItem.getSkuId());
                    refundReductionStockBO.setSpuId(orderItem.getSpuId());
                    refundReductionStockBO.setOrderId(orderRefundVO.getRefundId());
                    refundReductionStockBO.setShopId(orderRefundVO.getShopId());
                    refundReductionStockBO.setActivityId(orderItem.getActivityId());
                    if (Objects.equals(dbOrder.getSupplierDeliveryType(), 1) && !Objects.equals(dbOrder.getSupplierId(), 0L)) {
                        refundReductionStockBO.setSupplierProd(1);
                        refundReductionStockBO.setSkuId(orderItem.getSupplierSkuId());
                        refundReductionStockBO.setSpuId(orderItem.getSupplierSpuId());
                    }
                    return refundReductionStockBO;
                }).collect(Collectors.toList());
            }
            // 判断还原的是秒杀库存还是商品库存(处于秒杀活动期间，则还原秒杀库存)
            boolean isSecKillStock = false;
            Long activityId = null;
            if (OrderType.SECKILL.value().equals(dbOrder.getOrderType())
                    && !CollectionUtils.isEmpty(refundReductionStocks)) {
                activityId = refundReductionStocks.get(0).getActivityId();
                SeckillApiVO seckillApiVO = seckillFeignClient.getSeckillInfoById(activityId).getData();
                Date now = new Date();
                if (seckillApiVO != null
                        && seckillApiVO.getStatus() == 1
                        && seckillApiVO.getStartTime().compareTo(now) <= 0
                        && seckillApiVO.getEndTime().compareTo(now) >= 0) {
                    isSecKillStock = true;
                }
            }
            // 通知还原库存
            SendStatus sendStatus;
            if (isSecKillStock) {
                SecKillRefundDTO secKillRefundDTO = new SecKillRefundDTO(activityId, refundReductionStocks);
                sendStatus = seckillOrderRefundMqTemplate.syncSend(RocketMqConstant.SECKILL_ORDER_REFUND_TOPIC, new GenericMessage<>(secKillRefundDTO))
                        .getSendStatus();
            } else {
                sendStatus = orderRefundSuccessStockTemplate.syncSend(RocketMqConstant.ORDER_REFUND_SUCCESS_STOCK_TOPIC, new GenericMessage<>(refundReductionStocks))
                        .getSendStatus();
            }
            if (!Objects.equals(sendStatus, SendStatus.SEND_OK)) {
                throw new LuckException(ResponseEnum.EXCEPTION);
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelRefund(OrderRefundVO orderRefundVO) {


        // 更新退款状态为已取消
        OrderRefund orderRefund = new OrderRefund();
        orderRefund.setReturnMoneySts(ReturnProcessStatusEnum.FAIL.value());
        orderRefund.setCloseType(RefundCloseType.CANCEL.value());
        orderRefund.setCloseTime(new Date());
        orderRefund.setRefundId(orderRefundVO.getRefundId());
        orderRefund.setUserId(orderRefundVO.getUserId());
        update(orderRefund);

        closeOrderAndOrderItemRefundStatus(orderRefundVO);
    }

    /**
     * 关闭订单和订单项的退款状态
     *
     * @param orderRefundVo
     */
    private void closeOrderAndOrderItemRefundStatus(OrderRefundVO orderRefundVo) {
        Integer orderRefundSuccessCount = orderRefundMapper.countReturnProcessingItemByOrderId(orderRefundVo.getOrderId());

        // 更新订单
        // 如果有订单项退款成功，则订单状态为部分退款成功，否则为退款失败
        if (Objects.equals(orderRefundSuccessCount, 0)) {
            Order order = new Order();
            order.setOrderId(orderRefundVo.getOrderId());
            order.setRefundStatus(RefundStatusEnum.DISAGREE.value());
            orderService.update(order);
        }
        // 更新订单项状态
        if (Objects.equals(orderRefundVo.getRefundType(), RefundType.ALL.value())) {
            orderItemService.updateRefundStatusByOrderId(orderRefundVo.getOrderId(), RefundStatusEnum.DISAGREE.value());
        } else {
            // 拒绝退款
            OrderItem orderItem = new OrderItem();
            orderItem.setOrderItemId(orderRefundVo.getOrderItemId());
            orderItem.setRefundStatus(RefundStatusEnum.DISAGREE.value());
            orderItemService.update(orderItem);
        }

        //如果是赠品，需要处理关联赠品订单项
        List<OrderItemVO> giveawayOrderItems = orderItemService.getOrderItemByGiveawayOrderItemId(orderRefundVo.getUserId(), orderRefundVo.getOrderItemId());
        if (giveawayOrderItems.size() != 0) {
            List<OrderItem> list = new ArrayList<>();
            for (OrderItemVO orderItemVO : giveawayOrderItems) {
                OrderItem orderItems = mapperFacade.map(orderItemVO, OrderItem.class);
                orderItems.setRefundStatus(RefundStatusEnum.DISAGREE.value());
                list.add(orderItems);
            }
            orderItemService.updateBatch(list);
        }


    }

    /**
     * 不同意退款
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void disagreeRefund(OrderRefundDTO orderRefundParam, OrderRefundVO orderRefundVO) {
        int agreeStats = orderRefundMapper.disagreeRefund(orderRefundParam.getSellerMsg(), orderRefundParam.getRejectMessage(),
                orderRefundVO.getRefundId(), orderRefundVO.getReturnMoneySts(), orderRefundParam.getIsReceived(), orderRefundVO.getSupplierHandleStatus());
        if (agreeStats == 0) {
            throw new LuckException("订单退款状态已发生改变，请勿重复操作");
        }
        closeOrderAndOrderItemRefundStatus(orderRefundVO);

        // TODO 消息推送--拒绝退款
        ServerResponseEntity<List<SendNotifyBO>> orderServerResponseEntity = searchOrderFeignClient.listSendNotifyByOrderIds(Collections.singletonList(orderRefundVO.getOrderId()));
        if (orderServerResponseEntity.isFail()) {
            throw new LuckException(orderServerResponseEntity.getMsg());
        }
        List<SendNotifyBO> notifyBOList = orderServerResponseEntity.getData();
        SendNotifyBO sendNotifyBO = notifyBOList.get(0);
        sendNotifyBO.setSendType(SendTypeEnum.REFUSE_REFUND.getValue());
        sendNotifyBO.setRejectMessage(orderRefundParam.getRejectMessage());
        sendNotifyBO.setPrice(PriceUtil.toDecimalPrice(orderRefundVO.getRefundAmount()).toString());
        SendStatus sendBizStatus = sendNotifyToUserTemplate.syncSend(RocketMqConstant.SEND_NOTIFY_TO_USER_TOPIC, new GenericMessage<>(notifyBOList)).getSendStatus();
    }

    /**
     * 移交供应商
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void transferRefundOrderToSupplier(OrderRefundDTO orderRefundParam, OrderRefundVO orderRefundVo) {
        int agreeStats = orderRefundMapper.transferRefundOrderToSupplier(orderRefundVo.getSupplierHandleStatus(), orderRefundParam.getSupplierHandleStatus(),
                orderRefundVo.getRefundId(), orderRefundVo.getReturnMoneySts());
        // 退款移交供应商处理，需发送退款提醒给供应商
        ServerResponseEntity<List<SendNotifyBO>> orderServerResponseEntity = searchOrderFeignClient.listSendNotifyByOrderIds(Collections.singletonList(orderRefundVo.getOrderId()));
        if (orderServerResponseEntity.isFail()) {
            throw new LuckException(orderServerResponseEntity.getMsg());
        }
        SendNotifyBO notifyBO = orderServerResponseEntity.getData().get(0);
        notifyBO.setShopId(null);
        notifyBO.setSupplierId(orderRefundVo.getSupplierId());
        notifyBO.setPrice(PriceUtil.toDecimalPrice(orderRefundVo.getRefundAmount()).toString());
        notifyBO.setSendType(SendTypeEnum.LAUNCH_REFUND_TO_SUPPLIER.getValue());
        notifyBO.setBizId(orderRefundVo.getOrderId());
        notifyBO.setRemark(orderRefundVo.getBuyerDesc());
        notifyBO.setRejectMessage(BuyerReasonType.instance(orderRefundVo.getBuyerReason()).getCn());
        SendStatus sendBizStatus = sendNotifyToShopTemplate.syncSend(RocketMqConstant.SEND_NOTIFY_TO_SHOP_TOPIC, new GenericMessage<>(notifyBO)).getSendStatus();
        if (!Objects.equals(sendBizStatus, SendStatus.SEND_OK)) {
            throw new LuckException(ResponseEnum.EXCEPTION);
        }

        if (agreeStats == 0) {
            throw new LuckException("订单退款状态已发生改变，请勿重复操作");
        }
    }

    /**
     * 同意退款操作（生成结算记录）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int agreeRefund(OrderRefundVO orderRefundVo, OrderRefundDTO orderRefundParam) {
        Date nowDate = new Date();

        // 订单正在进行退款结算,之前已经同意过了，不需要再操作了
        if (orderRefundSettlementMapper.countByRefundId(orderRefundVo.getRefundId()) > 0) {
            return 0;
        }
        long freightAmount = checkLastRefund(orderRefundVo);
        // 生成退款结算记录
        OrderRefundSettlement orderRefundSettlement = new OrderRefundSettlement();
        orderRefundSettlement.setOrderId(orderRefundVo.getOrderId());
        orderRefundSettlement.setPayId(orderRefundVo.getPayId());
        orderRefundSettlement.setRefundId(orderRefundVo.getRefundId());
        orderRefundSettlement.setPayType(orderRefundVo.getPayType());
        orderRefundSettlement.setRefundAmount(orderRefundVo.getRefundAmount() + freightAmount);
        orderRefundSettlement.setOrderTotalAmount(orderRefundVo.getActualTotal());
        orderRefundSettlement.setUserId(orderRefundVo.getUserId());
        orderRefundSettlement.setRefundStatus(1);
        orderRefundSettlement.setCreateTime(nowDate);
        orderRefundSettlement.setUpdateTime(nowDate);
        orderRefundSettlementMapper.save(orderRefundSettlement);

        // 正在处理退款的状态,如果是仅退款到这里就更新一下处理时间，不是则不更新这时间
        // 获取退款单信息
        OrderRefundVO orderRefundDb = orderRefundMapper.getByRefundId(orderRefundParam.getRefundId());
        int updateStatus = orderRefundMapper.agreeRefund(orderRefundParam.getSellerMsg(), orderRefundVo.getRefundId(), orderRefundVo.getReturnMoneySts(),
                orderRefundParam.getIsReceived(), orderRefundDb.getApplyType(), orderRefundVo.getRefundAmount(), orderRefundVo.getPurchaseRefundAmount());
        if (updateStatus == 0) {
            return 0;
        }
        return 1;
    }

    private void agreeRefundUnreal(OrderRefundDTO orderRefundParam, OrderRefundVO orderRefundVo) {

        OrderSettlement orderSettlement = orderSettlementService.getByOrderId(orderRefundVo.getOrderId());
        if (orderSettlement == null) {
            logger.error("没有查询到支付记录，无法申请退款");
            return;
        }
        orderRefundVo.setPayId(orderSettlement.getPayId());
        orderRefundVo.setPayType(orderSettlement.getPayType());

        // -----最后一件运费计算-----------
        long freightAmount = 0L;
        orderRefundVo.setFreightAmount(0L);
        // 获取订单信息
        Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVo.getOrderId(), orderRefundVo.getUserId());
        if (Objects.equals(order.getStatus(), OrderStatus.PAYED.value())) {
            // 如果存在分销订单，则计算分销总金额
            List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderIds(order.getOrderId());
            // 获取所有的订单项总数
            int orderItemCount = orderItemList.size();
            //退款成功总数
            // 获取所有正在进行中的退款订单
            int refundCount = countSuccessItemNum(order.getOrderId());
            //最后一单
            if (Objects.equals(refundCount, orderItemCount - 1)) {
                if (order.getFreightAmount() > 0.0 && order.getPlatformFreeFreightAmount() >= 0.0) {
                    freightAmount = order.getFreightAmount() - order.getPlatformFreeFreightAmount();
                }
                // 单项退款，且平台减免运费---平台减免的运费要从商家钱包退还给平台，所以将运费添加到平台优惠金额中
                if (Objects.equals(orderRefundVo.getRefundType(),RefundType.SINGLE.value()) && order.getPlatformFreeFreightAmount() > 0.0) {
                    orderRefundVo.setPlatformRefundAmount(orderRefundVo.getPlatformRefundAmount() + order.getPlatformFreeFreightAmount());
                }
            }
            // 供应商发货的订单，放进去实际的支付运费金额，用于后续的供应商金额退款
            if(Objects.equals(order.getSupplierDeliveryType(),1) && !Objects.equals(order.getSupplierId(),0L)){
                orderRefundVo.setFreightAmount(freightAmount + Math.abs(order.getFreeFreightAmount()));
            }
        }
        // 如果是定金预售，需要注意下是两笔退款
        if(Objects.equals(order.getPreSaleType(), PreSaleType.DEPOSIT.value())){
            orderRefundVo.setPayIds(orderSettlement.getPayIds());
        }
        // 只有单个退款才需要加上运费
        if(Objects.equals(orderRefundVo.getRefundType(),RefundType.SINGLE.value())) {
            orderRefundVo.setRefundAmount(orderRefundVo.getRefundAmount() + freightAmount);
        }
//        orderRefundVo.setPurchaseRefundAmount(orderRefundVo.getPurchaseRefundAmount() + freightAmount);
        // 执行退款，真正意义上的退款，需要确保
        // 发送事务消息
        TransactionSendResult transactionSendResult = orderRefundTemplate.sendMessageInTransaction(RocketMqConstant.ORDER_REFUND_TOPIC, new GenericMessage<>(orderRefundVo), orderRefundParam);

        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            logger.error("MQ消息order-refund-topic发送执行异常");
            return;
        }
       logger.info("虚拟订单退款完成");
    }

    private long checkLastRefund(OrderRefundVO orderRefundDto) {
        if (Objects.equals(orderRefundDto.getRefundType(), RefundType.ALL.value())) {
            return 0L;
        }
        // 获取订单信息
        Order order = orderService.getOrderByOrderIdAndUserId(orderRefundDto.getOrderId(), orderRefundDto.getUserId());
        if (!Objects.equals(order.getStatus(), OrderStatus.PAYED.value())) {
            return 0L;
        }
        //所有订单项总数

        // 如果存在分销订单，则计算分销总金额
        List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderId(order.getOrderId());
        // 获取所有的订单项总数
        int orderItemCount = orderItemList.size();
        //退款成功总数
        // 获取所有正在进行中的退款订单
        int refundCount = countSuccessItemNum(order.getOrderId());
        if (Objects.equals(refundCount, orderItemCount - 1) && order.getFreightAmount() > 0.0) {
            //最后一单
            if (order.getPlatformFreeFreightAmount() == 0.0) {
                return order.getFreightAmount() - order.getPlatformFreeFreightAmount();
            }
        }
        return 0L;
    }

    @Override
    public Integer getRefundStatus(Long refundId) {
        return orderRefundMapper.getRefundStatus(refundId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createGroupUnSuccessRefundInfo(RefundNotifyBO refundNotifyBO) {
        Order dbOrder = orderService.getByOrderId(refundNotifyBO.getOrderId());
        List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderId(refundNotifyBO.getOrderId());
        // 生成退款单信息
        OrderRefund orderRefund = new OrderRefund();
        orderRefund.setRefundId(refundNotifyBO.getRefundId());
        orderRefund.setShopId(dbOrder.getShopId());
        orderRefund.setOrderId(refundNotifyBO.getOrderId());
        orderRefund.setRefundType(RefundType.ALL.value());
        orderRefund.setRefundAmount(refundNotifyBO.getRefundAmount());
        orderRefund.setApplyType(1);
        orderRefund.setIsReceived(0);
        orderRefund.setPlatformRefundAmount(dbOrder.getPlatformAmount());
        orderRefund.setBuyerReason(BuyerReasonType.GROUP_FAILED.value());
        orderRefund.setBuyerDesc("拼团失败：系统自动退款");
        orderRefund.setReturnMoneySts(ReturnProcessStatusEnum.APPLY.value());
        orderRefund.setSellerMsg("拼团失败：系统自动退款");
        orderRefund.setHandelTime(new Date());
        orderRefund.setUpdateTime(new Date());
        orderRefund.setUserId(dbOrder.getUserId());
        orderRefund.setOrderItemId(0L);
        orderRefund.setRefundCount(dbOrder.getAllCount());
        orderRefund.setPlatformRefundCommission(dbOrder.getPlatformCommission());
        orderRefund.setSupplierId(dbOrder.getSupplierId());
        orderRefund.setPurchaseRefundAmount(orderItemList.stream().mapToLong(OrderItem::getItemPurchaseAmount).sum());
        orderRefund.setPurPlatformRefundCommission(orderItemList.stream().mapToLong(OrderItem::getPurchasePlatformCommission).sum());
        orderRefundMapper.save(orderRefund);

        OrderRefundSettlement orderRefundSettlement = new OrderRefundSettlement();
        orderRefundSettlement.setOrderId(refundNotifyBO.getOrderId());
        orderRefundSettlement.setPayId(refundNotifyBO.getPayId());
        orderRefundSettlement.setRefundId(refundNotifyBO.getRefundId());
        orderRefundSettlement.setRefundAmount(refundNotifyBO.getRefundAmount());
        orderRefundSettlement.setOrderTotalAmount(refundNotifyBO.getRefundAmount());
        orderRefundSettlement.setRefundStatus(1);
        orderRefundSettlement.setUserId(dbOrder.getUserId());
        orderRefundSettlement.setPayType(dbOrder.getPayType());
        orderRefundSettlementMapper.save(orderRefundSettlement);

        refundSuccess(refundNotifyBO);
    }

    @Override
    public List<OrderRefundVO> getProcessingOrderRefundByOrderId(Long orderId) {
        return orderRefundMapper.getProcessingOrderRefundByOrderId(orderId);
    }

    @Override
    public Integer getSupplierHandleStatusByOrderId(Long orderId) {
        return orderRefundMapper.getSupplierHandleStatusByOrderId(orderId);
    }

    @Override
    public List<OrderRefundProdEffectRespVO> getProdRefundEffectByDateAndProdIds(List<Long> spuIds, Date startTime, Date endTime) {
        return mongoOrderRefundManager.getProdRefundEffectByDateAndProdIds(spuIds, startTime, endTime);
    }

    @Override
    public List<com.jf.cloud.api.order.vo.OrderRefundVO> getOrderRefundByOrderIdAndRefundStatus(Long orderId, Integer returnMoneySts) {
        return orderRefundMapper.getOrderRefundByOrderIdAndRefundStatus(orderId, returnMoneySts);
    }

    @Override
    public List<OrderRefundSimpleVO> listOrderIdsByRefundIds(List<Long> refundIds) {
        if (CollUtil.isEmpty(refundIds)) {
            return new ArrayList<>();
        }
        return orderRefundMapper.listOrderIdsByRefundIds(refundIds);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelWhenTimeOut(List<Long> refundIds) {
        List<Integer> returnMoneyStsList = new ArrayList<>(Arrays.asList(new Integer[]{1, 2, 3, 4}));
        Long createTime = DateUtil.offsetDay(new Date(), -Constant.MAX_REFUND_APPLY_TIME).getTime();
        Date now = new Date();
        for (Long refundId : refundIds) {
            OrderRefundVO orderRefundDb = orderRefundMapper.getByRefundId(refundId);
            if (Objects.isNull(orderRefundDb)) {
                continue;
            }
            OrderRefund orderRefund = new OrderRefund();
            Order order = new Order();
            order.setOrderId(orderRefundDb.getOrderId());
            order.setUpdateTime(now);
            orderRefund.setRefundId(orderRefundDb.getRefundId());
            orderRefund.setUpdateTime(now);
            //create_time <![CDATA[ < ]]> #{date} AND return_money_sts in(1,2,3,4) AND
            // 创建时间在15天内或处理退款状态不符合条件的不进行取消退款处理
            if (orderRefundDb.getCreateTime().getTime() > createTime || !returnMoneyStsList.contains(orderRefundDb.getReturnMoneySts())) {
                // 更新退款的更新时间，同步es、mongo中的退款数据
                orderRefundMapper.update(orderRefund);
                orderService.update(order);
                continue;
            }
            orderRefund.setReturnMoneySts(ReturnProcessStatusEnum.FAIL.value());
            orderRefund.setSellerMsg("申请退款超时");
            orderRefund.setCloseTime(now);
            orderRefund.setCloseType(RefundCloseType.TIME_OUT.value());
            orderRefund.setHandelTime(now);
            // 批量修改订单退款状态
            // 查询退款成功的订单商品数量
            Integer orderRefundSuccessCount = orderRefundMapper.countRefundSuccessRefundCountByOrderId(orderRefundDb.getOrderId());
            // 更新订单,如果有订单项退款成功，则订单状态为部分退款成功，否则为退款失败
            if (orderRefundSuccessCount > 0) {
                order.setRefundStatus(RefundStatusEnum.PARTIAL_SUCCESS.value());
            } else {
                order.setRefundStatus(RefundStatusEnum.DISAGREE.value());
            }

            // 更新订单项状态
            if (Objects.equals(orderRefundDb.getRefundType(), RefundType.ALL.value())) {
                orderItemService.updateRefundStatusByOrderId(orderRefundDb.getOrderId(), RefundStatusEnum.DISAGREE.value());
            } else {
                // 退款失败
                OrderItem orderItem = new OrderItem();
                orderItem.setOrderItemId(orderRefundDb.getOrderItemId());
                orderItem.setRefundStatus(RefundStatusEnum.DISAGREE.value());
                orderItemService.update(orderItem);
            }
            orderRefundMapper.update(orderRefund);
            orderService.update(order);
        }
    }

    @Override
    public com.jf.cloud.api.order.vo.OrderRefundVO getOrderRefundByRefundId(Long refundId) {
        OrderRefundVO orderRefundVO = getByRefundId(refundId);
        return mapperFacade.map(orderRefundVO, com.jf.cloud.api.order.vo.OrderRefundVO.class);
    }

    @Override
    public int countSuccessItemNum(Long orderId) {
        return orderRefundMapper.countSuccessItemNum(orderId);
    }

    @Override
    public EsOrderRefundBO saveMongoAndGetEsOrderRefundInfo(Long refundId) {
        MongoOrderRefundBO mongoOrderRefundBO = orderRefundMapper.mongoAndEsOrderRefundInfo(refundId);
        if (Objects.isNull(mongoOrderRefundBO)) {
            return null;
        }
        MongoOrderRefundBO mongoOrder = orderRefundMapper.mongoEsOrder(mongoOrderRefundBO.getOrderId());
        mongoOrderRefundBO.setShopName(mongoOrder.getShopName());
        mongoOrderRefundBO.setOrderType(mongoOrder.getOrderType());
        mongoOrderRefundBO.setFreightAmount(mongoOrder.getFreightAmount());
        mongoOrderRefundBO.setOrderStatus(mongoOrder.getOrderStatus());
        mongoOrderRefundBO.setWaitPurchase(mongoOrder.getWaitPurchase());
        mongoOrderRefundBO.setPayType(mongoOrder.getPayType());
        mongoOrderRefundBO.setPayId(mongoOrder.getPayId());
//        mongoOrderRefundBO.setAreaCode();
        // 处理包含赠品的退款订单
        List<Long> giveawayList = new ArrayList<>();
        if (Objects.nonNull(mongoOrderRefundBO.getReturnGiveawayIds())) {
            String[] split = mongoOrderRefundBO.getReturnGiveawayIds().split(",");
            giveawayList = Arrays.stream(split).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
        }
        List<MongoOrderRefundItemBO> mongoOrderRefundItems = orderRefundMapper.mongoAndEsOrderRefundItems(mongoOrderRefundBO.getOrderId(), mongoOrderRefundBO.getOrderItemId(), giveawayList);

        if (Objects.equals(mongoOrderRefundBO.getRefundType(), RefundType.SINGLE.value())) {
            mongoOrderRefundItems.get(0).setRefundAmount(mongoOrderRefundBO.getRefundAmount());
        }
        mongoOrderRefundBO.setOrderItems(mongoOrderRefundItems);

        // 单项商品退款,要把订单项中的商品数量换成退款的商品数量
        for (MongoOrderRefundItemBO mongoOrderRefundItem : mongoOrderRefundItems) {
            // 单项退款处理订单项
            if (Objects.equals(mongoOrderRefundBO.getRefundType(), RefundType.SINGLE.value())) {
                if (Objects.equals(mongoOrderRefundItem.getOrderItemId(), mongoOrderRefundBO.getOrderItemId())) {
                    mongoOrderRefundItem.setCount(mongoOrderRefundBO.getRefundCount());
                    mongoOrderRefundBO.setRefundScore(mongoOrderRefundItem.getRefundScore());
                }
            }
            if (Objects.equals(mongoOrderRefundBO.getRefundType(), RefundType.SINGLE.value())) {
                mongoOrderRefundItem.setRefundAmount(mongoOrderRefundBO.getRefundAmount());
            } else {
                mongoOrderRefundItem.setRefundAmount(mongoOrderRefundItem.getActualTotal());
            }
            for (OrderItemLangVO orderItemLangVO : mongoOrderRefundItem.getOrderItemLangList()) {
                if (Objects.equals(orderItemLangVO.getLang(), LanguageEnum.LANGUAGE_EN.getLang())) {
                    mongoOrderRefundItem.setSkuNameEn(orderItemLangVO.getSkuName());
                    mongoOrderRefundItem.setSpuNameEn(orderItemLangVO.getSpuName());
                } else {
                    mongoOrderRefundItem.setSkuNameZh(orderItemLangVO.getSkuName());
                    mongoOrderRefundItem.setSpuNameZh(orderItemLangVO.getSpuName());
                }
            }
        }
        mongoOrderRefundManager.save(mongoOrderRefundBO);
        return mapperFacade.map(mongoOrderRefundBO, EsOrderRefundBO.class);
    }

    @Override
    public PageVO<OrderRefundVO> userOrderRefundPage(PageDTO pageDTO, OrderRefundSearchDTO orderRefundSearchDTO) {
        Long userId = AuthUserContext.get().getUserId();
        orderRefundSearchDTO.setUserId(userId);
        PageVO<OrderRefundVO> pageVO = PageUtil.doPage(pageDTO, () -> orderRefundMapper.listUserOrderRefund(orderRefundSearchDTO));
        if (CollUtil.isEmpty(pageVO.getList())) {
            return pageVO;
        }
        List<Long> orderIds = pageVO.getList().stream().map(OrderRefundVO::getOrderId).collect(Collectors.toList());
        List<OrderItemVO> orderItemList = orderItemService.listOrderItemsByUserIdAndOrderIds(userId, orderIds);
        Map<Long, List<OrderItemVO>> orderItemMap = orderItemList.stream().collect(Collectors.groupingBy(OrderItemVO::getOrderId));
        List<Long> shopIds = pageVO.getList().stream().map(OrderRefundVO::getShopId).collect(Collectors.toList());
        List<ShopDetailVO> shops = shopDetailFeignClient.listByShopIds(shopIds).getData();
        Map<Long, String> shopNameMap = shops.stream().collect(Collectors.toMap(ShopDetailVO::getShopId, ShopDetailVO::getShopName));
        for (OrderRefundVO orderRefundVO : pageVO.getList()) {
            List<OrderItemVO> orderItems = orderItemMap.get(orderRefundVO.getOrderId());
            String shopName = shopNameMap.get(orderRefundVO.getShopId());
            if (CollUtil.isEmpty(orderItems) || Objects.isNull(shopName)) {
                continue;
            }
            orderRefundVO.setShopName(shopName);
            List<RefundOrderItemVO> refundOrderItems = mapperFacade.mapAsList(orderItems, RefundOrderItemVO.class);
            orderRefundVO.setOrderItems(refundOrderItems);

            // 整单退款不需要处理赠品和退款数量
            if (Objects.equals(orderRefundVO.getRefundType(), RefundType.ALL.value())) {
                giveawayRefundOrderItem(orderRefundVO);
                continue;
            }

            // 获取赠品id列表
            List<Long> giveawayList;
            if (StrUtil.isNotBlank(orderRefundVO.getReturnGiveawayIds())) {
                String[] split = orderRefundVO.getReturnGiveawayIds().split(",");
                giveawayList = Arrays.stream(split).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
            } else {
                giveawayList = new ArrayList<>();
            }

            // 单项退款处理订单项
            Iterator<RefundOrderItemVO> iterator = refundOrderItems.iterator();
            while (iterator.hasNext()) {
                RefundOrderItemVO refundOrderItem = iterator.next();
                // 移除不是退款或退款项赠品的订单项
                if (!Objects.equals(refundOrderItem.getOrderItemId(), orderRefundVO.getOrderItemId()) && !giveawayList.contains(refundOrderItem.getOrderItemId())) {
                    iterator.remove();
                    continue;
                }
                // 单项商品退款,要把订单项中的商品数量换成退款的商品数量
                if (Objects.equals(refundOrderItem.getOrderItemId(), orderRefundVO.getOrderItemId())) {
                    refundOrderItem.setCount(orderRefundVO.getRefundCount());
                    refundOrderItem.setRefundScore(orderRefundVO.getRefundScore());
                }
            }
            giveawayRefundOrderItem(orderRefundVO);
        }
        return pageVO;
    }

    /**
     * 处理赠品退款订单项
     * @param orderRefundVO
     */
    private void giveawayRefundOrderItem(OrderRefundVO orderRefundVO){
        Map<Long, List<RefundOrderItemVO>> map = orderRefundVO.getOrderItems().stream()
                .filter(s -> Objects.equals(s.getActivityType(), OrderActivityType.GIVEAWAY.value()))
                .collect(Collectors.groupingBy(RefundOrderItemVO::getActivityId));
        // 如果没有赠品，就不需要处理
        if (MapUtil.isEmpty(map)) {
            return;
        }
        // 将赠品放到对应的主订单项中
        Iterator<RefundOrderItemVO> iterator = orderRefundVO.getOrderItems().iterator();
        while (iterator.hasNext()) {
            RefundOrderItemVO refundOrderItemVO = iterator.next();
            // 移除赠品的订单项，进入下一个循环
            if (Objects.equals(refundOrderItemVO.getActivityType(), OrderActivityType.GIVEAWAY.value())) {
                iterator.remove();
                continue;
            }
            // 主订单项插入赠品订单项
            if (map.containsKey(refundOrderItemVO.getOrderItemId())) {
                refundOrderItemVO.setGiveawayList(map.get(refundOrderItemVO.getOrderItemId()));
            }
        }
    }

    @Override
    public AccountOrderDetailVO getAccountOrderDetail(Date startTime, Date endTime, String shopName, Long shopId) {
        return mongoOrderRefundManager.getAccountRefundOrderDetail(startTime, endTime, shopName, shopId);
    }

    @Override
    public PageShopAccountOrderVO listShopAccountDetail(Date startTime, Date endTime, String shopName, Integer pageSize, Integer pageNum) {
        return mongoOrderRefundManager.listShopRefundAccountDetail(startTime, endTime, shopName, pageSize, pageNum);
    }

    @Override
    public PageShopAccountOrderVO listOrderRefundInfo(Date startTime, Date endTime, Long shopId, String shopName, Integer pageSize, Integer pageNum) {
        if (Objects.isNull(pageNum) && Objects.isNull(pageSize)) {
            return mongoOrderRefundManager.listOrderRefundInfo(startTime, endTime, shopName);
        }
        return mongoOrderRefundManager.pageOrderRefundInfo(startTime, endTime, shopId, pageSize, pageNum);
    }


    /**
     * 判断退款单类型（1:整单退款,2:单个物品退款）
     * sysType,1.展示赠品信息，0.不展示
     */
    private void getRefundTypeByOrderItem(OrderRefundVO orderRefundVO, Integer sysType) {
        Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVO.getOrderId(), orderRefundVO.getUserId());
        orderRefundVO.setWaitPurchase(order.getWaitPurchase());
        if (Objects.equals(orderRefundVO.getRefundType(), RefundType.ALL.value())) {
            List<RefundOrderItemVO> items = orderRefundVO.getOrderItems();
            List<RefundOrderItemVO> reItems = new ArrayList<>();
            orderRefundVO.setRefundScore(items.stream().mapToLong(RefundOrderItemVO::getRefundScore).sum());
            //放入赠品信息
            if (Objects.equals(sysType, 1)) {
                List<Long> itemIds = items.stream().map(RefundOrderItemVO::getOrderItemId).collect(Collectors.toList());
                List<OrderItemVO> giveawayItems = orderItemService.getOrderItemByGiveawayOrderItemIds(itemIds, order.getUserId(), sysType);
                List<RefundOrderItemVO> itemVOS = mapperFacade.mapAsList(giveawayItems, RefundOrderItemVO.class);
                Map<Long, List<RefundOrderItemVO>> giveawayItemMap = itemVOS.stream().collect(Collectors.groupingBy(RefundOrderItemVO::getActivityId));
                for (RefundOrderItemVO orderItem : items) {
                    if (Objects.equals(orderItem.getActivityType(), OrderActivityType.GIVEAWAY.value())) {
                        continue;
                    }
                    // 放入赠品
                    if (giveawayItemMap.containsKey(orderItem.getOrderItemId())) {
                        orderItem.setGiveawayList(giveawayItemMap.get(orderItem.getOrderItemId()));
                    }
                    reItems.add(orderItem);
                }
            }
            orderRefundVO.setOrderItems(reItems);
        } else {
            OrderItemVO item = orderItemService.getByOrderItemId(orderRefundVO.getOrderItemId());
            orderRefundVO.setRefundScore(item.getUseScore());
            orderRefundVO.setFreightAmount(order.getFreightAmount());
            RefundOrderItemVO reItemVo = mapperFacade.map(item, RefundOrderItemVO.class);
            //放入赠品信息
            String returnGiveawayIds = orderRefundVO.getReturnGiveawayIds();
            if (StrUtil.isBlank(returnGiveawayIds) || Objects.equals(sysType, 0)) {
                return;
            }
            String[] split = returnGiveawayIds.split(StrUtil.COMMA);
            List<Long> itemIds = Arrays.stream(split).map(s -> Long.parseLong(s.trim())).collect(Collectors.toList());
            List<OrderItemVO> giveawayItems = orderItemService.getOrderItemByGiveawayOrderItemIds(itemIds, item.getUserId(), null);
            List<RefundOrderItemVO> itemVOS = mapperFacade.mapAsList(giveawayItems, RefundOrderItemVO.class);
            List<RefundOrderItemVO> reItems = new ArrayList<>();
            for (RefundOrderItemVO refundOrderItemVO : orderRefundVO.getOrderItems()) {
                if (refundOrderItemVO.getOrderItemId().equals(reItemVo.getOrderItemId())) {
                    refundOrderItemVO.setGiveawayList(itemVOS);
                    reItems.add(refundOrderItemVO);
                    break;
                }
            }
            orderRefundVO.setOrderItems(reItems);
        }
    }
}
